﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace T.FAS.Runtime.Base.Entity
{
    public class AbsElementJsonConverter : JsonConverter
    {
        string[] allOpe = new string[]
        {
            QueryOperator.Equal
            ,QueryOperator.NotEqual
            ,QueryOperator.LessThan
            ,QueryOperator.GreaterThan
            ,QueryOperator.GreaterEqualThan
            ,QueryOperator.LessEqualThan
            ,QueryOperator.Contains
            ,QueryOperator.NotContains
            ,QueryOperator.FixedLengthContains
            ,QueryOperator.StartsWith
            ,QueryOperator.EndsWith
            ,QueryOperator.Between
            ,QueryOperator.In
            ,QueryOperator.NotIn
        };

        public override bool CanRead => true;

        public override bool CanWrite => true;

        public override bool CanConvert(Type objectType)
        {
            return typeof(Filter) == objectType;
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jObj = serializer.Deserialize<JObject>(reader);
            return GetAbsElement(jObj);
        }

        public AbsElement GetAbsElement(JObject jObj)
        {
            IDictionary<string, JToken> dic = jObj;
            string elementType = dic["ElementType"].ToString();
            if (elementType == "Relation")
            {
                FRelation Relation = new FRelation();
                Relation.Relation = jObj.Value<string>("Relation");
                Validator(Relation);
                return Relation;
            }
            else if (elementType == "Group")
            {
                var filters = jObj.Value<JArray>("Filters");
                List<AbsElement> filterList = new List<AbsElement>();
                if (filters != null)
                {
                    foreach (var item in filters)
                    {
                        filterList.Add(GetAbsElement((JObject)item));
                    }
                }
                var extSetting = jObj.Value<JObject>(nameof(Group.ExtSetting));
                AdvancedFilterExtSetting advancedFilterExtSetting = null;
                if (extSetting != null)
                    advancedFilterExtSetting = JsonConvert.DeserializeObject<AdvancedFilterExtSetting>(extSetting.ToString());
                Group group = new Group
                {
                    Filters = filterList,
                    ExtSetting = advancedFilterExtSetting,
                };
                return group;
            }
            else
            {
                Filter filter = new Filter();
                filter.Code = jObj.Value<string>("Code");
                filter.Name = jObj.Value<string>("Name");
                filter.DataType = jObj.Value<string>("DataType");
                filter.Condition = jObj.Value<string>("Condition");
                filter.ValueType = (AdvancedQueryValueType)Enum.Parse(typeof(AdvancedQueryValueType), jObj.Value<int>("ValueType").ToString());
                filter.ValueName = jObj.Value<string>("ValueName");
                List<string> list = new List<string>();
                if (jObj["Value"] is JArray)
                {
                    var Values = jObj.Value<JArray>("Value");
                    foreach (JToken item in Values)
                    {
                        list.Add(item.ToString()?.Trim());
                    }
                }
                else
                {
                    list.Add(jObj.Value<string>("Value")?.Trim());
                }
                filter.Value = list;
                Validator(filter);
                return filter;
            }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteStartObject();
            writer.WritePropertyName("ElementType"); writer.WriteValue((value as AbsElement)?.ElementType);
            if (value is Group group)
            {
                writer.WritePropertyName("Filters"); writer.WriteRawValue(JsonConvert.SerializeObject(group.Filters));
                writer.WritePropertyName(nameof(Group.ExtSetting)); writer.WriteRawValue(JsonConvert.SerializeObject(group.ExtSetting));
            }
            if (value is Filter filter)
            {
                writer.WritePropertyName("Code"); writer.WriteValue(filter.Code);
                writer.WritePropertyName("Condition"); writer.WriteValue(filter.Condition);
                if (filter.Value.Count > 1)
                {
                    writer.WritePropertyName("Value"); writer.WriteRawValue(JsonConvert.SerializeObject(filter.Value));
                }
                else
                {
                    writer.WritePropertyName("Value"); writer.WriteValue(filter.Value[0]);
                }
                writer.WritePropertyName("Name"); writer.WriteValue(filter.Name);
                writer.WritePropertyName("DataType"); writer.WriteValue(filter.DataType);
                writer.WritePropertyName("ValueName"); writer.WriteValue(filter.ValueName);
                writer.WritePropertyName("ValueType"); writer.WriteValue(filter.ValueType);
            }
            if (value is FRelation Relation)
            {
                writer.WritePropertyName("Relation"); writer.WriteValue(Relation.Relation.ToString());
            }
            writer.WriteEndObject();
        }

        private void Validator(Filter filter)
        {
            if (filter == null) return;
            if (allOpe.Contains(filter.Condition) == false)
            {
                throw new Exception($"不支持的操作符：{filter.Condition}");
            }
            //根据元数据code的前端校验正则规范进行校验
            var code = filter.Code?.Trim();
            if (string.IsNullOrEmpty(code))
            {
                throw new Exception($"查询条件的Code不合法：{filter.Code}");
            }
            //其中code必须为 xxx.yyy格式，即使是自定义列，也为__UserDefineColumns.yyy 格式
            else if (code.Contains("."))
            {
                var codeArr = code.Split('.');
                if (codeArr.Length != 2 || !CodeRegValidator(codeArr[0]) || !CodeRegValidator(codeArr[1]))
                {
                    throw new Exception($"查询条件的Code不合法：{filter.Code}");
                }
            }
            //5+3的개새끼用Funcs.BuildDQAdvFilter()方法传参是只传一段式的ID，兼容一下
            else if (!CodeRegValidator(code))
            {
                throw new Exception($"查询条件的Code不合法：{filter.Code}");
            }
        }

        private void Validator(FRelation relation)
        {
            if (relation == null) return;
            var lower = relation.Relation.ToLower();
            if (lower != "and" && lower != "or")
            {
                throw new Exception($"不支持的关联关系：{relation.Relation}");
            }
        }

        private bool CodeRegValidator(string codePart)
        {
            // 定义正则表达式模式，注意 C# 中不需要斜杠定界符
            string pattern = @"^[a-zA-Z_][a-zA-Z_0-9]+$";

            // 执行匹配验证
            return Regex.IsMatch(codePart, pattern);
        }
    }
}